import json
import logging
import threading
from io import StringIO
from os import fork, remove
from os.path import exists, sep
from socket import AF_UNIX, SOCK_STREAM, socket

from apscheduler.schedulers.background import BackgroundScheduler

from .. import init_log, may_path
from ..config import MayConfig

socketfile = may_path + "may.sock"


class MayDaemon:
    def __init__(self) -> None:
        pass

    def do_operate(self, operate):
        logging.info("do operate %s", operate)
        try:
            if operate["name"] == "stop":
                code = self._stop()
                return {"code": 200, "msg": "success"}
            elif operate["name"] == "restart":
                code = self._stop()
                return {"code": 200, "msg": "stop success", "config_path": self.config_path}
            else:
                return {"code": 400, "msg": "bad request, unknow operation %s" % operate}
        except BaseException as e:
            logging.error("do operate %s fail", operate, exc_info=e)

    def bind_local_socket(self):
        if exists(socketfile):
            remove(socketfile)
        self.closed = False
        socketfd = socket(AF_UNIX, SOCK_STREAM)
        socketfd.bind(socketfile)
        socketfd.listen(5)
        while True:
            connfd, addr = socketfd.accept()
            sio = StringIO()
            data = "start flag"
            while "\n" not in data:
                data = connfd.recv(1024).decode("utf-8")
                sio.write(data)
            operate = json.loads(sio.getvalue())
            ret = self.do_operate(operate)
            data = json.dumps(ret)
            connfd.send(data.encode("utf-8"))
            connfd.close()
            if self.closed:
                socketfd.close()
                remove(socketfile)
                break

    def send_msg(self, operation):
        logging.debug("send message %s", operation)
        clientfd = socket(AF_UNIX, SOCK_STREAM)
        clientfd.connect(socketfile)
        clientfd.send(json.dumps(operation).encode("utf-8"))
        clientfd.send(b"\n")
        data = clientfd.recv(1024)
        clientfd.close()
        return json.loads(data.decode("utf-8"))

    def start(self, config_path, debug=False):
        if not debug:
            # run on background
            pid = fork()
            if pid:
                return pid

        # 解析配置文件
        self.config_path = config_path
        config = MayConfig(config_path)

        # 初始化日志
        init_log(may_path + "log" + sep + "may.log", debug)

        # 绑定本地socket，用于接收操作
        threading.Thread(target=self.bind_local_socket,
                         name="operation_thread").start()

        # 启动may server
        if config["servers_list_module"] == "yaml_file":
            from ..servers.yaml_servers import YamlFileServers
            self.may_server = YamlFileServers(config["servers_yaml"])

        # 启动定时任务器
        self.scheduler = BackgroundScheduler()
        self.scheduler.start()

    def _stop(self):
        self.closed = True

    def stop(self):
        logging.info("send stop msg")
        self.send_msg({
            "name": "stop"
        })

    def restart(self):
        logging.info("send restart msg")
        ret = self.send_msg({
            "name": "restart"
        })
        self.start(ret["config_path"])

    def status(self):
        pass
